<?php

namespace App\Utility;

use App\Utility\Pool\RedisPool;
use EasySwoole\Component\Pool\PoolManager;
use EasySwoole\EasySwoole\Logger;
use Swoole\Coroutine\Redis;
use EasySwoole\EasySwoole\Config;

class RedisTools{

    protected $redis;
    protected $options;

    public function __construct($queue = ''){
        $redis = PoolManager::getInstance()
            ->getPool(RedisPool::class)
            ->getObj(Config::getInstance()->getConf('REDIS.POOL_TIME_OUT'));
        $options = Config::getInstance()->getConf('REDIS');
        if ($redis) {
            $this->redis = $redis;
            if($queue){
                $options['queue'] = $options['queue'].$queue;
            }
            $this->options = $options;
        } else {
            //直接抛给异常处理，不往下
            throw new \Exception('error,Redis Pool is Empty');
        }
    }

    public function __destruct(){
        PoolManager::getInstance()->getPool(RedisPool::class)->recycleObj($this->redis);
    }

    /**
     * 获取指定 key 的值。
     * @param $name
     * @param null $default
     * @return null
     */
    public function get($name, $default = null){
        $key   = $this->getCacheKey($name);
        $value = $this->redis->get($key);
        if (is_null($value) || false === $value) {
            return $default;
        }
        return is_numeric($value) ? $value : $this->unPackData($value);
    }

    /**
     * 设置指定 key 的值
     * @param $name
     * @param $value
     * @param null $expire
     * @return mixed
     */
    public function set($name, $value, $expire = null){
        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }
        $key   = $this->getCacheKey($name);
        $expire= $this->getExpireTime($expire);
        $value = is_numeric($value) ? $value : $this->packData($value);
        if ($expire) {
            $result = $this->redis->setex($key, $expire, $value);
        } else {
            $result = $this->redis->set($key, $value);
        }
        return $result;
    }


    /**
     * 将 key 所储存的值加上给定的增量值
     * @param $name
     * @param int $step
     * @return mixed
     */
    public function inc($name, $step = 1){
        return $this->redis->incrBy($this->getCacheKey($name), $step);
    }

    /**
     * key 所储存的值减去给定的减量值
     * @param $name
     * @param int $step
     * @return mixed
     */
    public function dec($name, $step = 1){
        return $this->redis->decrBy($this->getCacheKey($name), $step);
    }

    /**
     * 获取指定 key 的值并删除key。
     * @param $name
     * @param null $default
     * @return null
     */
    public function pull($name){
        $result = $this->get($name);
        if ($result) {
            $this->delete($name);
            return $result;
        }
        return null;
    }

    /**
     * 如果key设置一个值
     * @param $name
     * @param $value
     * @param null $expire
     * @return mixed|null
     */
    public function remember($name, $value, $expire = null){
        if (!$this->has($name)) {
            return $this->set($name, $value, $expire);
        }
        return $this->get($name);
    }


    /**
     * 删除指定key。
     * @param $name
     * @return mixed
     */
    public function delete($name){
        return $this->redis->delete($this->getCacheKey($name));
    }

    /**
     * 检查给定 key 是否存在
     * @param $name
     * @return mixed
     */
    public function has($name){
        return $this->redis->exists($this->getCacheKey($name));
    }

    /**
     * 清除所有缓存
     * @return bool
     */
    public function clear(){
        $keys = $this->redis->keys($this->options['prefix'].'*');
        if ($keys) {
            $this->redis->del(...$keys);
        }
        return true;
    }

    /**
     * 获取缓存前缀
     * @param $name
     * @return string
     */
    protected function getCacheKey($name){
        return $this->options['prefix'].$name;
    }

    /**
     * 过期时间
     * @param $expire
     * @return int
     */
    protected function getExpireTime($expire){
        if ($expire instanceof \DateTime) {
            $expire = $expire->getTimestamp() - time();
        }
        return (int) $expire;
    }

    /**
     * 序列化数据
     * @param $data
     * @return string
     */
    protected function packData($data){
        return serialize($data);
    }

    /**
     * 反序列化数据
     * @param $data
     * @return mixed
     */
    protected function unPackData($data){
        return unserialize($data);
    }

//    //移除列表的最后一个元素
//    function rPop(){
//        return $this->redis->rPop($this->options['queue']);
//    }
//    //移出并获取列表的第一个元素
//    function lPop(){
//        return $this->redis->lPop($this->options['queue']);
//    }

    /******************************redis 列表（队列）部分********************************/

    /**
     * 生成队列
     * @param $data
     * @return mixed
     */
    public function lPush($data){
        if(is_array($data)){
            $data = json_encode($data);
        }
        return $this->redis->lpush($this->options['queue'], $data);
    }

    //移除列表的最后一个元素
    public function rPop(){
        $data = $this->redis->rPop($this->options['queue']);
        $return = json_decode($data,true);
        if ($return && (is_object($return)) || (is_array($return) && !empty(current($return)))) {
            return $return;
        }
        return $data;
    }

    //入列
    function push($data){
        return $this->redis->lpush($this->queue, json_encode($data));
    }
    //出列
    function read(){
        return json_decode($this->redis->rPop($this->queue),true);
    }

    //向集合中增加元素
    public function zAdd($key, $score, $value){
        return $this->redis->zAdd($key, $score, $value);
    }
    //统计集合成员数
    public function zCard($key){
        return $this->redis->zCard($key);
    }
    //返回有序集中，指定区间内的成员。
    public function zRange($key, $start, $end, $scores=null){
        return $this->redis->zRange($key, $start, $end, $scores);
    }

    //移除有序集中，指定分数（score）区间内的所有成员。
    public function zRemRangeByScore($key, $min, $max){
        return $this->redis->zRemRangeByScore($key, $min, $max);
    }

    //移除集合中一个成员
    public function zrem($key,$value){
        return $this->redis->zrem($key,$value);
    }

    //判断 member 元素是否是集合 key 的成员
    public function sismember($key, $value){
        return $this->redis->sismember($key, $value);
    }

    //返回集合中的所有成员
    public function sMembers($key){
        return $this->redis->sMembers($key);
    }

    //移除并返回集合中的一个随机元素
    public function sPop($key){
        return $this->redis->sPop($key);
    }

    //向集合中增加元素
    public function sAdd($key, $value){
        return $this->redis->sAdd($key, $value);
    }

    //所有给定集合的并集存储在 destination 集合中
    public function sUnionStore($dst, $key, $other_keys=null){
        return $this->redis->sUnionStore($dst, $key, $other_keys);
    }

    //获取集合的成员数
    public function scard($key){
        return $this->redis->scard($key);
    }

    //移除集合中一个成员
    public function srem($key,$value){
        return $this->redis->srem($key,$value);
    }


}
